#include "event_impl.h"

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    event_impl::event_impl()
    {
        m_bManuReset = false;
        m_bSignal = false;
        m_bInit = false;
    }

    event_impl::~event_impl()
    {
        term();
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    int event_impl::init()
    {
        int nRet = 0;

        if( !m_bInit )
        {
            pthread_mutex_init( &m_mutex, 0 );
            pthread_cond_init( &m_cond, 0 );
            m_bInit = true;
        }

        return nRet;
    }

    int event_impl::term()
    {
        int nRet = 0;

        if( m_bInit )
        {
            pthread_mutex_destroy( &m_mutex );
            pthread_cond_destroy( &m_cond );
            m_bInit = false;
        }

        m_bManuReset = false;
        m_bSignal = false;

        return nRet;
    }

    ////////////////////////////////////////////////////////////////////////////////////
    // 

    unsigned long event_impl::wait( unsigned long ulMilliseconds )
    {
        unsigned long ulRet = EVENT_WAIT_OBJECT_0;

        pthread_mutex_lock( &m_mutex );

        if( !m_bSignal )
        {
            if( 0xffffffff == ulMilliseconds )
            {
                pthread_cond_wait( &m_cond, &m_mutex );
            }
            else
            {
                struct timeval now = { 0 };
                struct timespec tm = { 0 };

                unsigned long ulSecond = ulMilliseconds / 1000;
                ulMilliseconds = ulMilliseconds % 1000;

                gettimeofday( &now, 0 );

                time_t t = ulMilliseconds * 1000000 + now.tv_usec * 1000;

                if( t > 1000000000 )
                {
                    tm.tv_sec += t / 1000000000;
                    t %= 1000000000;
                }

                tm.tv_sec += ulSecond + now.tv_sec;
                tm.tv_nsec = ( long )t;

                int ret = pthread_cond_timedwait( &m_cond, &m_mutex, &tm );

                if( ETIMEDOUT == ret )
                {
                    ulRet = EVENT_WAIT_TIMEOUT;
                }
            }
        }

        if( !m_bManuReset )
        {
            m_bSignal = false;
        }

        pthread_mutex_unlock( &m_mutex );

        return ulRet;
    }

    int event_impl::set_event_type( bool bManulReset )
    {
        int nRet = 0;
        m_bManuReset = bManulReset;
        return nRet;
    }

    int event_impl::reset_event()
    {
        int nRet = 0;
        pthread_mutex_lock( &m_mutex );
        m_bSignal = false;
        pthread_mutex_unlock( &m_mutex );
        return nRet;
    }

    int event_impl::set_event()
    {
        int nRet = 0;
        pthread_mutex_lock( &m_mutex );
        m_bSignal = true;
        pthread_cond_signal( &m_cond );
        pthread_mutex_unlock( &m_mutex );
        return nRet;
    }

    int event_impl::release()
    {
        int nRet = 0;

        term();
        put_back_lock();

        return nRet;
    }
} // xos
